/*
* Author: Chris Seguin
*
* This software has been developed under the copyleft
* rules of the GNU General Public License. Please
* consult the GNU General Public License for more
* details about use and distribution of this software.
*/
package org.acm.seguin.uml.line;
import java.awt.Point;
import java.awt.Rectangle;
/**
* Segment
*
*@author Chris Seguin
*@created July 28, 1999
*/
class Segment {
/*<Instance Variables>*/
private double A0;
private double A1;
private double B0;
private double B1;
private double m;
/*</Instance Variables>*/
/*<Constructors>*/
/**
* Constructor for the Segment object
*/
public Segment() {
A0 = 0;
A1 = 1;
B0 = 0;
B1 = 1;
m = 1.414;
}
/*</Setters>*/
/*<Getters>*/
/**
* Gets the Point attribute of the Segment object
*
*@param t Description of Parameter
*@return The Point value
*/
public Point getPoint(double t) {
return new Point((int) (A0 + t * A1), (int) (B0 + t * B1));
}
/**
* Gets the ParamFromDistance attribute of the Segment object
*
*@param dist Description of Parameter
*@return The ParamFromDistance value
*/
public double getParamFromDistance(double dist) {
if (dist > m) {
return (m - dist);
}
else {
return dist / m;
}
}
/*</Constructors>*/
/*<Setters>*/
/**
* Description of the Method
*
*@param left Description of Parameter
*@param right Description of Parameter
*/
public void reset(Rectangle left, Rectangle right) {
double X0 = left.getX() + left.getWidth() * 0.5;
double Y0 = left.getY() + left.getHeight() * 0.5;
double X1 = right.getX() + right.getWidth() * 0.5;
double Y1 = right.getY() + right.getHeight() * 0.5;
A0 = X0;
A1 = X1 - X0;
B0 = Y0;
B1 = Y1 - Y0;
m = Math.sqrt(A1 * A1 + B1 * B1);
}
/**
* Description of the Method
*
*@param left Description of Parameter
*@param right Description of Parameter
*/
public void reset(Point left, Point right) {
double X0 = left.getX();
double Y0 = left.getY();
double X1 = right.getX();
double Y1 = right.getY();
A0 = X0;
A1 = X1 - X0;
B0 = Y0;
B1 = Y1 - Y0;
m = Math.sqrt(A1 * A1 + B1 * B1);
}
/**
* Description of the Method
*
*@param left Description of Parameter
*@param right Description of Parameter
*/
public void reset(Rectangle left, Point right) {
double X0 = left.getX() + left.getWidth() * 0.5;
double Y0 = left.getY() + left.getHeight() * 0.5;
double X1 = right.getX();
double Y1 = right.getY();
A0 = X0;
A1 = X1 - X0;
B0 = Y0;
B1 = Y1 - Y0;
}
/**
* Description of the Method
*
*@param left Description of Parameter
*@param right Description of Parameter
*/
public void reset(Point left, Rectangle right) {
double X0 = left.getX();
double Y0 = left.getY();
double X1 = right.getX() + right.getWidth() * 0.5;
double Y1 = right.getY() + right.getHeight() * 0.5;
A0 = X0;
A1 = X1 - X0;
B0 = Y0;
B1 = Y1 - Y0;
m = Math.sqrt(A1 * A1 + B1 * B1);
}
/**
* Intersects the rectangle with the segment
*
*@param rect The rectangle
*@return The parameter of the location on the line, -1 if it does not
* intersect
*/
public double intersect(Rectangle rect) {
double left = rect.getX();
double right = rect.getX() + rect.getWidth();
double top = rect.getY();
double bottom = rect.getY() + rect.getHeight();
double leftSide = -1;
double rightSide = -1;
if (Math.abs(A1) > 0.0001) {
leftSide = (left - A0) / A1;
rightSide = (right - A0) / A1;
}
double topSide = -1;
double bottomSide = -1;
if (Math.abs(B1) > 0.001) {
topSide = (top - B0) / B1;
bottomSide = (bottom - B0) / B1;
}
if (inRectangle(leftSide, rect)) {
return leftSide;
}
else if (inRectangle(rightSide, rect)) {
return rightSide;
}
else if (inRectangle(topSide, rect)) {
return topSide;
}
else if (inRectangle(bottomSide, rect)) {
return bottomSide;
}
return -1;
}
/**
* Determines the distance between a point and a segment
*
*@param point The point
*@return Returns the distance between the segment and the point or -1
* if the point is closer to an end
*/
public double distanceToPoint(Point point) {
double vX1 = A1;
double vY1 = B1;
double vX2 = point.getX() - A0;
double vY2 = point.getY() - B0;
double magV2Square = vX2 * vX2 + vY2 * vY2;
double magV1Square = vX1 * vX1 + vY1 * vY1;
double dotProduct = vX1 * vX2 + vY1 * vY2;
if ((dotProduct < 0) || (dotProduct > magV1Square)) {
return -1.0;
}
double dist = Math.sqrt(magV2Square - dotProduct * dotProduct / magV1Square);
return dist;
}
/**
* Returns a parameter on the line that is a given distance from the end of
* the segment
*
*@param desiredDistance the desired distance
*@return the parameter
*/
public double findFromEnd(double desiredDistance) {
double p = Math.sqrt(A1 * A1 + B1 * B1);
return 1 - desiredDistance / p;
}
/**
* Returns a point above the line
*
*@param t Description of Parameter
*@param dist Description of Parameter
*@return Description of the Returned Value
*/
public Point aboveLine(double t, double dist) {
if (Math.abs(A1) < 0.001) {
Point temp = getPoint(t);
return new Point((int) (temp.getX() - dist), (int) temp.getY());
}
Point p4 = getPoint(t);
double x4 = p4.getX();
double y4 = p4.getY();
double a = B1 * B1 + A1 * A1;
double b = -2 * y4 * a;
double c = y4 * y4 * a - A1 * A1 * dist * dist;
double y5 = (-b + Math.sqrt(b * b - 4 * a * c)) / (2 * a);
double x5 = -B1 * (y5 - y4) / A1 + x4;
return new Point((int) x5, (int) y5);
}
/**
* Returns a point below the line
*
*@param t Description of Parameter
*@param dist Description of Parameter
*@return Description of the Returned Value
*/
public Point belowLine(double t, double dist) {
if (Math.abs(A1) < 0.001) {
Point temp = getPoint(t);
return new Point((int) (temp.getX() + dist), (int) temp.getY());
}
Point p4 = getPoint(t);
double x4 = p4.getX();
double y4 = p4.getY();
double a = B1 * B1 + A1 * A1;
double b = -2 * y4 * a;
double c = y4 * y4 * a - A1 * A1 * dist * dist;
double y5 = (-b - Math.sqrt(b * b - 4 * a * c)) / (2 * a);
double x5 = -B1 * (y5 - y4) / A1 + x4;
return new Point((int) x5, (int) y5);
}
/**
* Determines whether a particular point on the line is on the rectangle
*
*@param t the parameter that specifies the point
*@param rect the rectangle
*@return true if the point is in the rectangle
*/
private boolean inRectangle(double t, Rectangle rect) {
if ((t < 0) || (t > 1)) {
return false;
}
double X0 = A0 + A1 * t;
double Y0 = B0 + B1 * t;
double left = rect.getX();
double right = rect.getX() + rect.getWidth();
double top = rect.getY();
double bottom = rect.getY() + rect.getHeight();
return (left <= X0) && (right >= X0) && (top <= Y0) && (bottom >= Y0);
}
/*</Getters>*/
}